export const metadata = {
  title: "Core",
  description:
    "Get started with the framework agnostic core package of T3 Env.",
};

# Core

The core package can be used in any framework of your choice. To use it, figure out what prefix your framework uses for exposing environment variables to the client. For example, Astro uses `PUBLIC_`, while Vite uses `VITE_`. You should be able to find this in the frameworks documentation.

<Steps>

### Install dependencies

First, install the core package:

```bash
npm install @t3-oss/env-core zod

# or using JSR
deno add jsr:@t3-oss/env-core
```

<Callout>

Although we'll use Zod as examples throughout these docs, you can use any validator that supports [Standard Schema](https://github.com/standard-schema/standard-schema).

</Callout>

<Callout>

`@t3-oss/env-core` requires a minimum of `typescript@5.0.0`.

</Callout>

<Callout>

`@t3-oss/env-core` is an ESM only package. Make sure that your tsconfig uses a module resolution that can read `package.json#exports` (`Bundler` is recommended).

</Callout>

### Create your schema

Then, you can create your schema like so:

<Callout>

The file below is named `env.ts`, but you can name it whatever you want. Some frameworks even generate a `env.d.ts` file that will collide with `env.ts`, which means you will have to name it something else.

</Callout>

```ts title="src/env.ts"
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },

  /**
   * The prefix that client-side variables must have. This is enforced both at
   * a type-level and at runtime.
   */
  clientPrefix: "PUBLIC_",

  client: {
    PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },

  /**
   * What object holds the environment variables at runtime. This is usually
   * `process.env` or `import.meta.env`.
   */
  runtimeEnv: process.env,

  /**
   * By default, this library will feed the environment variables directly to
   * the Zod validator.
   *
   * This means that if you have an empty string for a value that is supposed
   * to be a number (e.g. `PORT=` in a ".env" file), Zod will incorrectly flag
   * it as a type mismatch violation. Additionally, if you have an empty string
   * for a value that is supposed to be a string with a default value (e.g.
   * `DOMAIN=` in an ".env" file), the default value will never be applied.
   *
   * In order to solve these issues, we recommend that all new projects
   * explicitly specify this option as true.
   */
  emptyStringAsUndefined: true,
});
```

Remove the `clientPrefix` and `client` properties if you only want the environment variables to exist on the server.

<Callout type="warning">

While defining both the client and server schemas in a single file provides the best developer experience,
it also means that your validation schemas for the server variables will be shipped to the client.
If you consider the **names** of your variables sensitive, you should split your schemas into two files.

```ts title="src/env/server.ts"
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  runtimeEnv: process.env,
});
```

```ts title="src/env/client.ts"
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";

export const env = createEnv({
  clientPrefix: "PUBLIC_",
  client: {
    PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },
  runtimeEnv: process.env,
});
```

</Callout>

For all available options, see [Customization](/docs/customization).

You'll notice that if your `clientPrefix` is `PUBLIC_`, you won't be allowed to enter any other keys in the `client` object without getting type-errors. Below you can see we get a descriptive error when we set `VITE_PUBLIC_API_URL` instead of `PUBLIC_API_URL`:

![invalid client prefix](https://user-images.githubusercontent.com/51714798/234410449-271d7afe-b541-45bf-acaa-134cbec4c51a.png)

This client prefix is also enforced at runtime to make sure validation works on both the server and client.

### Validate schema on build (recommended)

The steps required to validate your schema on build will vary from framework to framework, but you'll usually be able to import the env file in your configuration file, or in any file that's pulled in the beginning of the build process.

Note that some frameworks don't import their environment variables in their configuration file.

### Use your schema

Then, import the `env` object in your application and use it, taking advantage of type-safety and auto-completion:

```ts title="some-api-endpoint.ts"
import { env } from "~/env"; // On server

export const GET = async () => {
  // do fancy ai stuff
  const magic = await fetch("...", {
    headers: { Authorization: env.OPEN_AI_API_KEY },
  });
  // ...
};
```

</Steps>

## Additional strictness for `runtimeEnv`

<Callout type="info">

Exactly one of `runtimeEnv` and `runtimeEnvStrict` should be specified.

</Callout>

If your framework doesn't bundle all environment variables by default, but instead only bundles the ones you use, you can use the `runtimeEnvStrict` option to make sure you don't forget to add any variables to your runtime.

```ts title="src/env.ts"
import { createEnv } from "@t3-oss/env-core";

export const env = createEnv({
  clientPrefix: "PUBLIC_",
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  client: {
    PUBLIC_PUBLISHABLE_KEY: z.string().min(1),
  },
  /**
   * Makes sure you explicitly access **all** environment variables
   * from `server` and `client` in your `runtimeEnv`.
   */
  runtimeEnvStrict: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
    PUBLIC_PUBLISHABLE_KEY: process.env.PUBLIC_PUBLISHABLE_KEY,
  },
});
```

When using the strict option, missing any of the variables in `runtimeEnvStrict` will result in a type error:

![missing runtimeEnv](https://user-images.githubusercontent.com/51714798/234409775-fee3edbd-a73b-415a-829f-28f6f6092707.png)
